/**
 * www.easyplatform.cn ©2016
 */
package cn.easyplatform.studio.web.views.impl;

import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.entities.beans.table.TableField;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.cmd.entity.GetEntityCmd;
import cn.easyplatform.studio.context.Contexts;
import cn.easyplatform.studio.vos.ArgsVo;
import cn.easyplatform.studio.vos.FunctionVo;
import cn.easyplatform.studio.web.editors.EditorCallback;
import cn.easyplatform.studio.web.editors.Tablable;
import cn.easyplatform.studio.web.editors.view.Funcs;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.web.ext.cmez.CMeditor;
import cn.easyplatform.web.ext.cmez.DropEvent;
import cn.easyplatform.web.ext.zul.BandboxExt;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zk.ui.ext.Disable;
import org.zkoss.zul.*;

import java.util.Map;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
class LogicView extends AbstractView<String> {

    private CMeditor editor;

    private Popup hint;

    private String table;

    private Bandbox tablebox;

    private Grid grid;

    private Funcs funcs;

    /**
     * @param cb
     */
    protected LogicView(EditorCallback<String> cb, Component component) {
        super(component, cb);
        table = ((Tablable) cb).getTable();
    }

    @Override
    public void doOverlapped() {
        super.doOverlapped();
        win.setHeight("650px");
        win.setWidth("950px");
    }

    protected void createHeader(Component parent) {
        North north = new North();
        north.setSize("0px");
        north.setBorder("none");
        hint = new Popup();
        hint.setId("logicView_popup_hint");
        hint.setParent(north);
        north.setParent(parent);
    }

    @Override
    protected void createContent(Component parent) {
        Executions.createComponents("~./include/views/subPage.zul", parent,
                null);
        for (Component comp : parent.getFellows()) {
            if(comp.getId().equals("functionsInc")) {
                funcs = new Funcs((cn.easyplatform.web.ext.zul.Include) comp, "200px");
            } else if (comp.getId().equals("logicView_cmeditor_code")) {
                editor = (CMeditor) comp;
                editor.setTheme(Contexts.getUser().getEditorTheme());
                editor.setHflex("1");
                editor.setVflex("1");
                editor.setTheme(Contexts.getUser().getEditorTheme());
                editor.setFocus(true);
                editor.setValue(cb.getValue());
                editor.setDroppable(EntityType.TABLE.getName());
                editor.addEventListener(Events.ON_DROP, this);
                editor.addEventListener(Events.ON_CHANGING, this);
                editor.addEventListener(CMeditor.ON_CURSOR_ACTIVITY, this);
            }
        }

    }

    @Override
    protected void createFooter(Component parent) {
        South south = new South();
        south.setBorder("none");
        south.setSize("35px");
        south.setHflex("1");
        Hlayout toolbar = new Hlayout();
        toolbar.setSpacing("10px");
        toolbar.setVflex("1");
        toolbar.setSclass("epstudio-top pull-right");
        Button pretty = new Button(Labels.getLabel("button.beautify"));
        pretty.setIconSclass("z-icon-magic");
        pretty.setMold("bs");
        pretty.setId("logicView_button_beautify");
        pretty.setSclass("btn-light btn-sm");
        pretty.addEventListener(Events.ON_CLICK, this);
        pretty.setParent(toolbar);
        Button save = new Button(Labels.getLabel("button.save"));
        save.setId("logicView_button_save");
        save.setIconSclass("z-icon-save");
        save.setMold("bs");
        save.setSclass("btn-primary btn-sm");
        save.setParent(toolbar);
        save.addEventListener(Events.ON_CLICK, this);
        toolbar.setParent(south);
        south.setParent(parent);
        East east = new East();
        east.setVflex("1");
        east.setSize("200px");
        east.setMinsize(200);
        east.setSplittable(true);
        east.setCollapsible(true);
        east.setBorder("none");
        /**
         * 新增函数功能
         */
        Idspace is = new Idspace();
        is.setHflex("1");
        is.setVflex("1");
        Executions.createComponents("~./include/editor/entity/logic.zul", is,
                null);
//        is.setParent(east);

        Caption cp = new Caption();
        cp.setParent(east);
        cp.setLabel(Labels.getLabel("entity.table") + ": ");
        tablebox = new Bandbox();
        tablebox.setId("logicView_bandbox_search");
        tablebox.setWidth("120px");
        tablebox.setValue(table);
        tablebox.addEventListener(Events.ON_OK, this);
        tablebox.addEventListener(Events.ON_OPEN, this);
        tablebox.setParent(cp);
        grid = new Grid();
        grid.setId("logicView_grid_result");
        Columns cols = new Columns();
        cols.setSizable(true);
        cols.setParent(grid);
        Column col = new Column(Labels.getLabel("entity.name"));
        col.setHflex("1");
        col.setParent(cols);
        col = new Column(Labels.getLabel("entity.desp"));
        col.setHflex("1");
        col.setParent(cols);
        col = new Column(Labels.getLabel("entity.type"));
        col.setWidth("60px");
        col.setParent(cols);
        grid.setHflex("1");
        grid.setVflex("1");
        grid.appendChild(new Rows());
        grid.setParent(east);
        east.setParent(parent);
        if (!Strings.isBlank(table))
            showTable(table);
    }

    private void showTable(String table) {
        grid.getRows().getChildren().clear();
        TableBean e = (TableBean) StudioApp.execute(null, new GetEntityCmd(table));
        if (e != null && e.getFields() != null) {
            for (TableField tf : e.getFields()) {
                Row row = new Row();
                row.setValue(tf);
                row.setDraggable(EntityType.TABLE.getName());
                row.appendChild(new Label(tf.getName()));
                row.appendChild(new Label(tf.getDescription()));
                row.appendChild(new Label(tf.getType().name()));
                row.setParent(grid.getRows());
            }
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onEvent(Event event) throws Exception {
        if (event.getTarget() == editor) {
            if (event.getName().equals(CMeditor.ON_CURSOR_ACTIVITY)) {
                showHint((Map<String, Object>) event.getData());
            } else if (event.getName().equals(Events.ON_DROP)) {
                doDrop((DropEvent) event);
            }
        } else {
            if (event.getTarget() == tablebox) {
                String table = null;
                if (event instanceof OpenEvent)
                    table = (String) ((OpenEvent) event).getValue();
                else
                    table = tablebox.getValue();
                showTable(table);
            } else {
                String value = (String) editor.getValue();
                if ("logicView_button_beautify".equals(event.getTarget().getId())) {
                    if (!Strings.isBlank(value))
                        editor.exeCmd("formatAll");
                } else {
                    cb.setValue(value);
                    event.getTarget().getRoot().detach();
                    onCloseClick(win);
                }
            }
        }
    }

    private void doDrop(DropEvent evt) {
        String[] content = editor.getValue().toString().split("\n");
        StringBuilder sb = new StringBuilder();
        if(evt.getDragged() instanceof Row) {
            Row row = (Row) evt.getDragged();
            TableField tf = row.getValue();
            String text = (row.getRoot() == editor.getRoot() ? "$" : "@")
                    + tf.getName();
            for (int i = 0; i < content.length; i++) {
                if (i == evt.getLine()) {
                    char[] cs = content[i].toCharArray();
                    if (cs.length == evt.getCh())
                        sb.append(content[i]).append(text);
                    else {
                        for (int j = 0; j < cs.length; j++) {
                            if (j == evt.getCh()) {
                                sb.append(text);
                            } else
                                sb.append(cs[j]);
                        }
                    }
                    sb.append("\n");
                } else {
                    sb.append(content[i]).append("\n");
                }
            }
            editor.insertText(evt.getLine(), evt.getCh(), text);
        } else if(evt.getDragged() instanceof Listitem) {
            Listitem row = (Listitem) evt.getDragged();
            String text = row.getValue();
            FunctionVo fv = StudioApp.getFunctionDesc(text);
            editor.insertText(evt.getLine(), evt.getCh(), text + fv.getExp());
            funcs.updateScroll(sb, fv);
        }

    }

    private void showHint(Map<String, Object> objs) {
        int line = (Integer) objs.get("line");
        int ch = (Integer) objs.get("ch");
        String[] content = editor.getValue().toString().split("\n");
        if (line >= content.length)
            return;
        char[] cs = content[line].toCharArray();
        if (ch >= cs.length)
            return;
        StringBuilder sb = new StringBuilder();
        String prefix = null;
        for (int pos = ch - 1; pos >= 0; pos--) {
            if (!Character.isLetterOrDigit(cs[pos])) {
                if (cs[pos] == '.') {
                    sb.reverse();
                    prefix = sb.toString();
                    sb.setLength(0);
                    continue;
                } else {
                    if (cs[pos] == '#' && prefix != null)
                        sb.append(cs[pos]);
                    break;
                }
            }
            sb.append(cs[pos]);
        }
        sb.reverse();
        String target = null;
        if (prefix == null)
            target = "";
        else {
            target = sb.toString();
            sb.setLength(0);
        }
        sb.append(prefix == null ? "" : prefix);
        for (int pos = ch; pos < cs.length; pos++) {
            if (!Character.isLetterOrDigit(cs[pos])) {
                if (cs[pos] != '(')
                    sb.setLength(0);
                break;
            }
            sb.append(cs[pos]);
        }
        String suffix = sb.toString();
        sb.setLength(0);
        if (Strings.isBlank(target)) {
            if (!Strings.isBlank(suffix)) {
                FunctionVo vo = StudioApp.getFunctionDesc(suffix);
                if (vo != null) {
                    funcs.updateScroll(sb, vo);
                }
//                    createHint(sb, vo, ((Number) objs.get("left")).intValue(),
//                            ((Number) objs.get("top")).intValue());
            }
        } else if (!Strings.isBlank(suffix)) {
            FunctionVo vo = StudioApp.getFunctionDesc(target + "." + suffix);
            if (vo != null) {
                funcs.updateScroll(sb, vo);
            }
//                createHint(sb, vo, ((Number) objs.get("left")).intValue(),
//                        ((Number) objs.get("top")).intValue());
        }
    }
//
//    private void createHint(StringBuilder sb, FunctionVo vo, int left, int top) {
//        sb.append("<ul class=\"list-group\">");
//        if (vo.getArgs() != null) {
//            for (ArgsVo av : vo.getArgs()) {
//                sb.append("<li class=\"list-group-item\">");
//                sb.append("<h4 class=\"list-group-item-heading\">")
//                        .append(vo.getName()).append(av.getName())
//                        .append("</h4>");
//                sb.append("<p class=\"list-group-item-text\">")
//                        .append(av.getDesc()).append("</p>");
//                sb.append("</li>");
//            }
//        }
//        if (vo.getExamples() != null) {
//            for (String s : vo.getExamples()) {
//                sb.append("<li class=\"list-group-item\">");
//                String[] cs = s.split("\n");
//                for (int i = 0; i < cs.length; i++) {
//                    if (!cs[i].trim().equals("")) {
//                        cs[i] = cs[i].replaceFirst("\t", "");
//                        sb.append(cs[i].replaceAll("\t", "&emsp;"));
//                        if (i < cs.length - 1)
//                            sb.append("</br>");
//                    }
//                }
//                sb.append("</li>");
//            }
//        }
//        sb.append("</ul>");
//        Html html = (Html) hint.getFirstChild();
//        if (html == null) {
//            html = new Html();
//            hint.appendChild(html);
//        }
//        html.setContent(sb.toString());
//        hint.open(left, top);
//    }
}
